package com.cyys.modules.system.service.user;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cyys.common.dataScope.DataScope;
import com.cyys.common.ql.AR;
import com.cyys.common.services.CyysBaseService;
import com.cyys.common.utils.MD5Util;
import com.cyys.common.utils.StringUtil;
import com.cyys.common.utils.date.DateUtil;
import com.cyys.modules.core.model.TreeBuilder;
import com.cyys.modules.core.sysParam.SystemConfigureUtil;
import com.cyys.modules.core.sysParam.SystemConstants;
import com.cyys.modules.core.sysParam.UserUtil;
import com.cyys.modules.system.dao.user.MenuDao;
import com.cyys.modules.system.dao.user.RoleDao;
import com.cyys.modules.system.dao.user.UserDao;
import com.cyys.modules.system.model.user.Menu;
import com.cyys.modules.system.model.user.Role;
import com.cyys.modules.system.model.user.User;
import com.cyys.modules.system.service.thirdInterface.SmsActivateService;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service("userService")
@Transactional(readOnly = true)
public class UserService extends CyysBaseService<UserDao, User> {

    @Resource
    private RoleDao roleDao;

    @Resource
    private MenuDao menuDao;

    @Resource
    private SmsActivateService smsActivateService;

    /**
     * 获取单个对象
     *
     * @param id
     * @return
     * @
     */
    public User getById(String id)  {
        User user = dao.selectById(id);
        user.setRoleList(roleDao.getRoleByUserId(id));
        return user;
    }

    @Transactional(readOnly = false)
    public AR save(User user)  {
        User entity = getByUserName(user.getUsername());
        if (entity != null) {
            return AR.failed("登录账号已存在");
        }
        if(StringUtil.isNotBlank(user.getPhone()) && dao.getByPhone(user.getPhone())!=null){
            return AR.failed("手机号已绑定其他用户，请重新输入");
        }
        user.setPassword(MD5Util.calcMD5(user.getPassword()));
        user.setDatePwdUpdate(new Date());
        dao.insert(user);
        UserUtil.add(user);  //缓存用户数据
        return AR.ok("新增用户成功");
    }


    @Transactional(readOnly = false)
    public AR update(User user)  {
        if(StringUtil.isNotBlank(user.getUsername())) {
            User t_user = getByUserName(user.getUsername());
            if (t_user != null && !(t_user.getId()).equals(user.getId())) {
                return AR.failed("登录账号已存在");
            }
        }
        if(StringUtil.isNotBlank(user.getPhone())){
            User t_user = getByPhone(user.getPhone());
            if (t_user != null && !(t_user.getId()).equals(user.getId())) {
                return AR.failed("手机号已绑定其他用户，请重新输入");
            }
        }
        if(StringUtil.isNotBlank(user.getPassword())) {
            user.setPassword(MD5Util.calcMD5(user.getPassword()));
            user.setDatePwdUpdate(new Date());
        }
        dao.updateById(user);
        UserUtil.modify(user);  //缓存用户数据
        return AR.ok("更新用户成功");
    }

    @Transactional(readOnly = false)
    public void updateById(User user)  {
       dao.updateById(user);
    }

    public User getByUserName(String username)  {
        return dao.getByUserName(username);
    }

    @Transactional(readOnly = false)
    public AR shiroLogin(String username, String password, String loginType)  {
        Boolean mutiOrg = Boolean.valueOf(SystemConfigureUtil.get(SystemConstants.MUTI_ORG));
        User user = null;
        if("2".equals(loginType)){//验证码登录,此时username为手机号，password为验证码
            user = dao.getByPhone(username);
        }else{
            user = dao.getByUserName(username);
        }
        if (user != null) {
            //判断用户密码输入错误次数是否有限制,为0无限制
            int lockNum = Integer.parseInt(SystemConfigureUtil.get(SystemConstants.PWD_LOCK_NUM));
            int lockHour = Integer.parseInt(SystemConfigureUtil.get(SystemConstants.PWD_LOCK_HOUR));
            Date lockDate = DateUtil.addHour(user.getLockTime(), lockHour);
            if(lockNum > 0){
                if (user.getLockStatus() == 1){
                    //判断是否解锁
                    if(!lockDate.before(new Date())){  //未解锁
                        lockDate = DateUtil.addHour(user.getLockTime(), lockHour);
                        return AR.failed("账号被锁定 " + lockNum + "小时，解锁时间为" + DateUtil.format(lockDate,"yyyy-MM-dd HH:mm:ss"));
                    }else{
                        //更新密码次数,已到时间解锁
                        user.setPwdCount(0);
                    }
                }
            }

            if (user.getDisable().equals("1")) {
                return AR.failed("用户禁止登陆！");
            }
            //账号密码登录方式
            if (!"2".equals(loginType) && !user.getPassword().equals(MD5Util.calcMD5(password))) {
                if(lockNum > 0){
                    user.setPwdCount(user.getPwdCount() + 1);
                    if(user.getPwdCount() == lockNum){
                        user.setLockTime(new Date());
                        user.setLockStatus(1);
                        dao.updateById(user);
                        return AR.failed("账号被锁定 " + lockNum + "小时，解锁时间为" + DateUtil.format(lockDate,"yyyy-MM-dd HH:mm:ss"));
                    }else{
                        dao.updateById(user);
                        return AR.failed("密码错误" + user.getPwdCount() + ",输入错误" + lockNum + "次后将被账号将被锁定");
                    }
                }else{
                    return AR.failed("账号或密码输入错误");
                }
            }
            //验证码登录方式
            if ("2".equals(loginType)){
                AR ar= smsActivateService.judgeActivateCode(username, password);
                if(ar.getCode()!=0){//验证失败
                    return AR.failed(ar.getMsg());
                }
            }
            // 查询用户权限
            user.setRoleList(roleDao.getRoleByUserId(user.getId()));
            //判断是否系统开发人员,判断是否设置了角色
            if (isSystemDeveloper(user) || (user.getRoleList() != null && user.getRoleList().size() > 0)) {
                List<Menu> menuList;
                if(isSystemDeveloper(user)){    //系统开发人员全部权限
                    QueryWrapper<Menu> qw = new QueryWrapper<>();
                    qw.orderByAsc("sort");
                    menuList = menuDao.selectList(qw);
                }else{
                    String[] roleIds = new String[user.getRoleList().size()];
                    for (int i = 0; i < user.getRoleList().size(); i++) {
                        roleIds[i] = user.getRoleList().get(i).getId();
                    }
                    menuList = menuDao.getMenuByRoleIds(roleIds);
                }
                // 转化为菜单树
                List<Menu> menuListTree = TreeBuilder.buildByRecursive(menuList, "0");
                user.setMenuList(menuList);
                Set<String> permissions = new HashSet<>();
                //转化为shiro权限String
                for (Menu menu : menuList) {
                    permissions.add(menu.getShiro());
                }
                //是否开启多机构
                if(mutiOrg){
                    if(!isSystemDeveloper(user) && StringUtil.isEmpty(user.getOrgId())){
                        return AR.failed("此用户未设置机构，请联系管理员进行设置！");
                    }
                }
                user.setPermissions(permissions);
                user.setMenuListTree(menuListTree);
            }else{
                return AR.failed("此用户未设置任何权限，请联系管理员进行设置");
            }
            //更新最后登陆时间
            user.setDateLastLogin(new Date());
            user.setLockStatus(0);
            user.setPwdCount(0);
            dao.updateById(user);
            return AR.ok(user,"登录成功");
        } else {
            if("2".equals(loginType)){//验证码登录
                return AR.failed("手机号对应的账号不存在！");
            }
            return AR.failed("用户名不存在！");
        }
    }

    @Transactional(readOnly = false)
    public AR editPwd(String id, String oldPassword, String password)  {
        if (StringUtil.isBlank(id)) {
            return AR.failed("用户编号不能为空。");
        } else {
            User user = dao.selectById(id);
            if (user == null) {
                return AR.failed("用户不存在。");
            } else if (!user.getPassword().equals(MD5Util.calcMD5(oldPassword))) {
                return AR.failed("密码错误。");
            } else {
                user.setPassword(MD5Util.calcMD5(password));
                user.setDatePwdUpdate(new Date());
                dao.updateById(user);
                return AR.ok("密码修改成功。");
            }
        }
    }

    @Transactional(readOnly = false)
    public AR updatePwdByPhoneCode(String phone, String code, String newPwd)  {
        if (StringUtil.isBlank(phone)) {
            return AR.failed("手机号不能为空");
        }else if (StringUtil.isBlank(code)) {
            return AR.failed("验证码不能为空");
        }else if (StringUtil.isBlank(newPwd)) {
            return AR.failed("新密码不能为空");
        }
        User user= this.getByPhone(phone);
        if(user== null){
            return AR.failed("找不到该手机号对应的账号");
        }
        AR ar= smsActivateService.judgeActivateCode(phone, code);
        if(ar.getCode()!=0){//验证失败
            return AR.failed(ar.getMsg());
        }
        User updateUser= new User();
        updateUser.setId(user.getId());
        updateUser.setPassword(MD5Util.calcMD5(newPwd));
        updateUser.setDatePwdUpdate(new Date());
        dao.updateById(updateUser);
        return AR.ok("密码修改成功。");
    }

    /**
     * 删除或者恢复数据
     *
     * @param id
     * @param isDelete 1:删除数据; 0:恢复数据
     * @return AjaxJson
     */
    @Transactional(readOnly = false)
    public AR logicById(String id, Integer isDelete)  {
        if (id.equals("1")) {
            return AR.failed("此用户是系统开发人员，不允许删除。");
        }
        dao.deleteById(id);
        if (isDelete == 1) {
            return AR.ok("删除成功");
        } else {
            return AR.ok("恢复成功");
        }
    }

    /**
     * 根据条件查询数据
     * @param page
     * @param param
     * @param mutiOrg 是否开启机构管理
     */
    public IPage<User> list(Page page, User param, Boolean mutiOrg) {
        QueryWrapper qw= new QueryWrapper(param);
        qw.orderByDesc("date_create");
        IPage<User> iPage = null;
        if(mutiOrg) { //是否开启机构管理
            iPage= selectPageByScope(page , new QueryWrapper(param), new DataScope());
        }else{
            iPage = dao.selectPage(page, qw);
        }
        List<User> returnList = Lists.newArrayList();
        for (User user : iPage.getRecords()){
            List<Role> roles = roleDao.getRoleByUserId(user.getId());
            user.setRoleList(roles);
            returnList.add(user);
        }
        iPage.setRecords(returnList);
        return iPage;
    }

    /**
     * 是否系统超级管理员
     * @return
     */
    protected Boolean isSystemDeveloper(User user) {
        return user.getId().equals("1") ? true : false;
    }

    public User getByPhone(String phone) {
        return dao.getByPhone(phone);
    }
}
